package com.xiatl.cgi.server.cgi.utils;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 签名工具类
 */
public class SignUtil {

    /**
     * 签名
     *
     * @param obj    请求参数
     * @param path   请求接口。 例子：“http://localhost:8080/request/test”, 传入“/request/test”
     * @param secret secret
     * @return 签名字符串
     */
    public static String sign(JSONObject obj, String path, String secret, String timestamp) {
        if (obj == null) {
            return StringUtils.EMPTY;
        }
        String sign = md5(getBaseString(obj, path, secret, timestamp));
        return sign.toUpperCase();
    }


    /**
     * 根据排序结果，拼接参数值。并在最后面加上&md5key=(分配的加密key)
     */
    private static String getBaseString(JSONObject obj, String path, String secret, String timestamp) {
        //移除含有的Sign参数
//        if (obj.containsKey("sign")) {
//            obj.remove("sign");
//        }
        // 参数排序
        LinkedHashMap<String, Object> sortMap = sortJSONObject(obj);
        List<String> paramList = new ArrayList<>();
        for (String key : sortMap.keySet()) {
            Object value = sortMap.get(key);
            if (value == null) {
                continue;
            }
            if (value instanceof Map || value instanceof List) {
                paramList.add(String.format("%s=%s", key, JSONObject.toJSONString(value)));
            } else {
                paramList.add(String.format("%s=%s", key, value.toString()));
            }
        }
        return String.join("&", paramList) + "&md5key=" + secret + "&path=" + path + "&timestamp=" +timestamp;
    }


    /**
     * 1、请求参数名提取后，转小写
     * <p>
     * 2、将小写的参数名按照字符串升序排序
     */
    @SuppressWarnings("unchecked")
    private static LinkedHashMap<String, Object> sortJSONObject(JSONObject obj) {
        LinkedHashMap<String, Object> result = new LinkedHashMap<>();
        Set<String> keySet = obj.keySet().stream().sorted(Comparator.comparing(String::toLowerCase)).collect(Collectors.toCollection(LinkedHashSet::new));
        for (String key : keySet) {
            Object value = obj.get(key);
            if (value == null) {
                continue;
            }
            key = key.toLowerCase();
            if (value instanceof JSONObject) {
                result.put(key, sortJSONObject((JSONObject) value));
            } else if (value instanceof JSONArray) {
                result.put(key, ((JSONArray) value).stream().map(o -> {
                    if (o instanceof JSONObject) {
                        return sortJSONObject((JSONObject) o);
                    }
                    return o;
                }).collect(Collectors.toList()));
            } else {
                result.put(key, value);
            }
        }
        return result;
    }

    private static String md5(String str) {
        String re = null;
        byte[] encrypt;
        try {
            byte[] tem = str.getBytes();
            MessageDigest md5 = MessageDigest.getInstance("md5");
            md5.reset();
            md5.update(tem);
            encrypt = md5.digest();
            StringBuilder sb = new StringBuilder();
            for (byte t : encrypt) {
                String s = Integer.toHexString(t & 0xFF);
                if (s.length() == 1) {
                    s = "0" + s;
                }
                sb.append(s);
            }
            re = sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return re;
    }

}
